#include <stdio.h>
#include <stdlib.h> //malloc
#include <string.h> //memcpy
#include <unistd.h> //sleep
#include "single_res_queue.h"

#define IDLE_FLAG_BIT  (0x80000000) //空闲状态flag,用来识别重复释放,增强队列健壮性

/*
 * 销毁资源管理Queue
 */
int single_res_queue_destroy(single_res_queue_t* q)
{
    if (q==NULL || q->q_size==0) return -1;
    int size = sizeof(single_res_queue_t)+sizeof(unsigned int)*2*q->q_size;
    LOCK(q->lock);
    q->q_size = 0;
    UNLOCK(q->lock);
    
    DESTROY_LOCK(q->lock);
    memset(q,0,size);
    free(q);

    return 0;
}
/*
 * 初始化资源管理Queue
 */
single_res_queue_t* single_res_queue_init(unsigned int size)
{
    unsigned int i = 0;
    if(size == 0) return NULL;
    
    single_res_queue_t* q = (single_res_queue_t*)malloc(
    sizeof(single_res_queue_t)+sizeof(unsigned int)*2*size);
    if (q == NULL) return NULL;
    
    q->q_size = size;
    q->cnt    = 0;
    q->w      = 0;
    LOCK_INIT(q->lock,0);
    for (i=0; i<size; i++)
    {
        q->data[i] = i|IDLE_FLAG_BIT;
        q->data[size+i] = i;
    }

    return q;
}
/*
 * 申请资源
 */
unsigned int single_res_queue_apply(single_res_queue_t* q)
{
    unsigned int rv = -1;
    if (q == NULL) return rv;

    LOCK(q->lock);
    
    if (q->cnt != q->q_size) 
    {
        q->data[q->w]&=~IDLE_FLAG_BIT;
        rv = q->data[q->w];
        q->w++;
        __sync_add_and_fetch(&q->cnt,1);
    }
    
    UNLOCK(q->lock);

    return rv;
}
/*
 * 释放资源
 */
unsigned int single_res_queue_release(single_res_queue_t* q,unsigned int id)
{
    unsigned int rv = -1;
    if (q==NULL || id>=q->q_size) return rv;
    
    LOCK(q->lock);
    
    if (q->cnt && 0==(IDLE_FLAG_BIT & q->data[q->data[q->q_size+id]])) 
    {
        q->w--;
        if (q->data[q->w] != id)
        {
            unsigned int*idx = &q->data[q->q_size];
            unsigned int old = idx[id];
            unsigned int t   = q->data[q->w];
            
            idx[t]  = old;
            idx[id] = q->w;
            
            q->data[q->w] = q->data[old];
            q->data[old]  = t;
        } 

        q->data[q->w] |= IDLE_FLAG_BIT;
        __sync_sub_and_fetch(&q->cnt,1);
        
    }

    UNLOCK(q->lock);
    
    return 0;
}

void dump_single_res_queue(single_res_queue_t* q)
{
    if (q==NULL) return;
    
    printf("\nQ size = %u ,cnt = %u\n", q->q_size, q->cnt);
    printf("     w = %u\n", q->w);
    #if(USE_FREE_LOCK)
    printf("w_lock = %u\n", q->lock_w);
    #endif
    unsigned int i = 0;
    unsigned int*idx = &q->data[q->q_size];
    
    for (i=0; i< q->q_size; i++)
    {
        if (q->data[i]&IDLE_FLAG_BIT)
            printf("  %04u ", q->data[i]&(~IDLE_FLAG_BIT));
        else
            printf(" [%04u]", q->data[i]);
        if ((i+1)%20 == 0) printf("\n");
    }
    printf("\nidx:\n");
    for (i=0; i< q->q_size; i++)
    {
        printf ("  %04u ", idx[i]);
        if((i+1)%20 == 0) printf("\n");
    }
    for (i=0; i< q->q_size; i++)
    {
        if ((q->data[idx[i]]&(~IDLE_FLAG_BIT)) != i)
        {
            printf("ERR: idx[%u] = %u, q->data[%u]=%u\n", i,idx[i],idx[i],q->data[idx[i]]);
        }
    }
    printf("\n");
    return;
}